//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// StatisticsDlg.cpp : implementation file
//
//#include "stdafx.h"
#include "emule.h"
#include "StatisticsDlg.h"
#include "UploadQueue.h"
#include "ColorFrameCtrl.h"
#include "WebServer.h"
#include "muuli_wdr.h"

#define ID_EXPORT_HTML 20001

// CStatisticsDlg dialog

BEGIN_EVENT_TABLE(CStatisticsDlg,wxPanel)
  EVT_MENU(ID_EXPORT_HTML,CStatisticsDlg::ExportHTMLEvent)
END_EVENT_TABLE()

//IMPLEMENT_DYNAMIC(CStatisticsDlg, CDialog)
CStatisticsDlg::CStatisticsDlg(wxWindow* pParent /*=NULL*/)
  : wxPanel(pParent,CStatisticsDlg::IDD) /*, m_DownloadOMeter( _I_DO_NOTHING_HERE_ ),m_Statistics(4),m_UploadOMeter(3)*/
{
  SetBackgroundColour(GetColour(wxSYS_COLOUR_WINDOW));
  wxSizer* content=statsDlg(this,TRUE);
  content->Show(this,TRUE);

  m_DownloadOMeter=(COScopeCtrl*)FindWindowByName("dloadScope");
  m_UploadOMeter=(COScopeCtrl*)FindWindowByName("uloadScope");
  m_Statistics=(COScopeCtrl*)FindWindowByName("otherScope");
  stattree=wxStaticCast(FindWindowByName("statTree"),wxTreeCtrl);

#if 0
  COScopeCtrl* tmp=new COScopeCtrl(3,this);
  testSizer->Add(tmp,1,wxGROW|wxALL|wxALIGN_CENTRE|wxLEFT,5);
  testSizer->Layout();

  m_DownloadOMeter=*tmp;
#endif

#if 0
  // let's play around a bit
  // can't. preferences are created later
  tmp->SetRange(0,theApp.glob_prefs->GetMaxGraphDownloadRate()+4,0);
  tmp->SetRange(0,theApp.glob_prefs->GetMaxGraphDownloadRate()+4,1);
  tmp->SetRange(0,theApp.glob_prefs->GetMaxGraphDownloadRate()+4,2);
  tmp->SetYUnits(GetResString(IDS_KBYTESEC));
#endif
}

CStatisticsDlg::~CStatisticsDlg()
{
}

void CStatisticsDlg::Init()
{
  // called after preferences get initialised
  m_DownloadOMeter->SetBackgroundColor(RGB(0, 0, 64)) ;
  m_DownloadOMeter->SetGridColor(RGB(192, 192, 255)) ;
  m_DownloadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 0) ;
  m_DownloadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 1) ;
  m_DownloadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 2) ;
  m_DownloadOMeter->SetPlotColor( RGB(0, 128, 0),0) ;
  m_DownloadOMeter->SetPlotColor( RGB(0, 210, 0),1) ;
  m_DownloadOMeter->SetPlotColor( RGB(128, 255, 128),2) ;
  m_DownloadOMeter->SetYUnits(GetResString(IDS_KBYTESEC)) ;

  m_UploadOMeter->SetBackgroundColor(RGB(0, 0, 64)) ;
  m_UploadOMeter->SetGridColor(RGB(192, 192, 255)) ;
  m_UploadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 0) ;
  m_UploadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 1) ;
  m_UploadOMeter->SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 2) ;
  m_UploadOMeter->SetPlotColor( RGB(140, 0, 0)  ,0) ;
  m_UploadOMeter->SetPlotColor( RGB(200, 0, 0)  ,1) ;
  m_UploadOMeter->SetPlotColor( RGB(255, 128, 128),2) ;
  m_UploadOMeter->SetYUnits(GetResString(IDS_KBYTESEC)) ;

  m_Statistics->SetBackgroundColor(RGB(0, 0, 64)) ;
  m_Statistics->SetGridColor(RGB(192, 192, 255)) ;
  m_Statistics->SetRanges(0, theApp.glob_prefs->GetStatsMax()) ;
  m_Statistics->autofitYscale=true;
  
  m_Statistics->SetPlotColor( RGB(150, 150, 255),0) ;
  m_Statistics->SetPlotColor( RGB(192,   0, 192),1) ;
  m_Statistics->SetPlotColor( RGB(255, 192, 255),2) ;
  m_Statistics->SetPlotColor( RGB(255, 255, 128),3) ;
  m_Statistics->SetYUnits("") ;
  m_Statistics->SetXUnits(GetResString(IDS_TIME));

  // setup tree
  wxTreeItemId root=stattree->AddRoot(_("Statistics"));
  h_transfer= stattree->InsertItem(root,0L,GetResString(IDS_FSTAT_TRANSFER));
  tran0= stattree->AppendItem(h_transfer,GetResString(IDS_FSTAT_WAITING));

  h_upload = stattree->AppendItem(h_transfer,GetResString(IDS_TW_UPLOADS));
  up1= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up2= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up3= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up4= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up5= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up6= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up7= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up8= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up9= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));
  up10= stattree->AppendItem(h_upload,GetResString(IDS_FSTAT_WAITING));

  h_download = stattree->AppendItem(h_transfer,GetResString(IDS_TW_DOWNLOADS));
  down1= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down2= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down3= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down4= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down5= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down6= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));
  down7= stattree->AppendItem(h_download,GetResString(IDS_FSTAT_WAITING));

  h_connection = stattree->AppendItem(root,GetResString(IDS_FSTAT_CONNECTION));
  con1= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con2= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con12=stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con13=stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con3= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con4= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con5= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con6= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con7= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con8= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));
  con9= stattree->AppendItem(h_connection,GetResString(IDS_FSTAT_WAITING));

  h_clients = stattree->AppendItem(root,GetResString(IDS_CLIENTS));
  cli1= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
		cli_versions[0]= stattree->AppendItem(cli1,GetResString(IDS_FSTAT_WAITING));
		cli_versions[1]= stattree->AppendItem(cli1,GetResString(IDS_FSTAT_WAITING));
		cli_versions[2]= stattree->AppendItem(cli1,GetResString(IDS_FSTAT_WAITING));
		cli_versions[3]= stattree->AppendItem(cli1,GetResString(IDS_FSTAT_WAITING));
  cli8= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
  cli2= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
		cli_versions[4]= stattree->AppendItem(cli2,GetResString(IDS_FSTAT_WAITING));
		cli_versions[5]= stattree->AppendItem(cli2,GetResString(IDS_FSTAT_WAITING));
		cli_versions[6]= stattree->AppendItem(cli2,GetResString(IDS_FSTAT_WAITING));
		cli_versions[7]= stattree->AppendItem(cli2,GetResString(IDS_FSTAT_WAITING));
  cli3= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
		cli_versions[8]= stattree->AppendItem(cli3,GetResString(IDS_FSTAT_WAITING));
		cli_versions[9]= stattree->AppendItem(cli3,GetResString(IDS_FSTAT_WAITING));
		cli_versions[10]= stattree->AppendItem(cli3,GetResString(IDS_FSTAT_WAITING));
		cli_versions[11]= stattree->AppendItem(cli3,GetResString(IDS_FSTAT_WAITING));
  cli4= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
  cli5= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
  cli9= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
  cli6= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
  cli7= stattree->AppendItem(h_clients,GetResString(IDS_STATS_FILTEREDCLIENTS));

  h_servers = stattree->AppendItem(root,GetResString(IDS_FSTAT_SERVERS));
  srv1= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv2= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv3= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv4= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv5= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv6= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv7= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv8= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));
  srv9= stattree->AppendItem(h_servers,GetResString(IDS_FSTAT_WAITING));

  h_shared = stattree->AppendItem(root, GetResString(IDS_SHAREDFILES) );
  shar1= stattree->AppendItem(h_shared,GetResString(IDS_FSTAT_WAITING));
  shar2= stattree->AppendItem(h_shared,GetResString(IDS_FSTAT_WAITING));
  shar3= stattree->AppendItem(h_shared,GetResString(IDS_FSTAT_WAITING));
  
  stattree->Expand(root);
  stattree->Expand(h_transfer);//,TVE_EXPAND);
  stattree->Expand(h_connection);//,TVE_EXPAND);
  stattree->Expand(h_clients);//,TVE_EXPAND);
  stattree->Expand(h_servers);//,TVE_EXPAND);
  stattree->Expand(h_shared);// ,TVE_EXPAND);
  stattree->Expand(h_upload);//,TVE_EXPAND);
  stattree->Expand(h_download);//,TVE_EXPAND);

  RepaintMeters();

  m_ilastMaxConnReached = 0;
  peakconnections = 0;
  totalconnectionchecks = 0;
  averageconnections = 0;
  activeconnections = 0;  
}


void CStatisticsDlg::RepaintMeters() {
	m_DownloadOMeter->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0)) ;
	m_DownloadOMeter->SetGridColor(theApp.glob_prefs->GetStatsColor(1)) ;
	m_DownloadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(4) ,0) ;
	m_DownloadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(3) ,1) ;
	m_DownloadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(2) ,2) ;

	m_UploadOMeter->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0)) ;
	m_UploadOMeter->SetGridColor(theApp.glob_prefs->GetStatsColor(1)) ;
	m_UploadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(7) ,0) ;
	m_UploadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(6) ,1) ;
	m_UploadOMeter->SetPlotColor( theApp.glob_prefs->GetStatsColor(5) ,2) ;

	m_Statistics->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0)) ;
	m_Statistics->SetGridColor(theApp.glob_prefs->GetStatsColor(1)) ;
	m_Statistics->SetPlotColor( theApp.glob_prefs->GetStatsColor(8),0) ;
	m_Statistics->SetPlotColor( theApp.glob_prefs->GetStatsColor(10),1) ;
	//m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(10),2) ;
	m_Statistics->SetPlotColor( theApp.glob_prefs->GetStatsColor(9),3) ;

	SetupLegend( IDC_C0_2, 0 ,1);
	SetupLegend( IDC_C0_3, 1 ,1);
	SetupLegend( IDC_C0,   2 ,1);
	
	SetupLegend( IDC_C1_2, 0 ,2 );
	SetupLegend( IDC_C1_3, 1 ,2 );
	SetupLegend( IDC_C1,   2 ,2 );
	

	SetupLegend( IDC_S0, 0 ,3);
	SetupLegend( IDC_S1, 1 ,3);
	//SetupLegend( IDC_S2, 2 ,3);
	SetupLegend( IDC_S3, 3 ,3);
}

void CStatisticsDlg::SetupLegend( int ResIdx, int ElmtIdx, int legendNr){
  //CRect Rect;
  
  //GetDlgItem( ResIdx )->GetWindowRect( Rect );
  //ScreenToClient( Rect );
  CColorFrameCtrl* ctrl=(CColorFrameCtrl*)FindWindow(ResIdx);

  if(ctrl==NULL) {
    printf("no control (%d)\n",ResIdx);
    exit(1);
  }

  if (legendNr==1){
    //m_Led1[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
    //m_Led1[ ElmtIdx ].SetBackgroundColor( m_DownloadOMeter.GetPlotColor( ElmtIdx ) );
    //m_Led1[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
    ctrl->SetBackgroundColor((COLORREF)m_DownloadOMeter->GetPlotColor(ElmtIdx));
    ctrl->SetFrameColor((COLORREF)RGB(0,0,0));
  } else if (legendNr==2) {
    //m_Led2[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
    //m_Led2[ ElmtIdx ].SetBackgroundColor( m_UploadOMeter.GetPlotColor( ElmtIdx ) );
    //m_Led2[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
    ctrl->SetBackgroundColor((COLORREF)m_UploadOMeter->GetPlotColor(ElmtIdx));
    ctrl->SetFrameColor((COLORREF)RGB(0,0,0));
  } else if (legendNr==3){
    //m_Led3[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
    //m_Led3[ ElmtIdx ].SetBackgroundColor( m_Statistics.GetPlotColor( ElmtIdx ) );
    //m_Led3[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
    ctrl->SetBackgroundColor((COLORREF)m_Statistics->GetPlotColor(ElmtIdx));
    ctrl->SetFrameColor((COLORREF)RGB(0,0,0));
  }
}


void CStatisticsDlg::SetCurrentRate(float uploadrate, float downloadrate) {
	double m_dPlotDataUp[ 3 ];
	double m_dPlotDataDown[ 3 ];
	int myStats[6];

	// current rate
	m_dPlotDataDown[2]=downloadrate;
	m_dPlotDataUp[2]=uploadrate;

        if (maxDown<downloadrate) maxDown=downloadrate;
                                                                                
        // Websever [kuchin]
        UpDown* updown=new UpDown();
        updown->upload = uploadrate;
        updown->download = downloadrate;
        theApp.webserver->AddStatsLine(updown);

	// averages
	m_dPlotDataDown[0]=	GetAvgDownloadRate(AVG_SESSION);
	m_dPlotDataUp[0]=	GetAvgUploadRate(AVG_SESSION);

	m_dPlotDataDown[1]=	GetAvgDownloadRate(AVG_TIME);
	m_dPlotDataUp[1]=	GetAvgUploadRate(AVG_TIME);

	// show
	m_DownloadOMeter->AppendPoints(m_dPlotDataDown);
	m_UploadOMeter->AppendPoints(m_dPlotDataUp);


	// get Partialfiles summary
	activeconnections = theApp.listensocket->GetOpenSockets();

	theApp.downloadqueue->GetDownloadStats(myStats);
	m_dPlotDataMore[0]=(activeconnections/3);//myStats[0];
	m_dPlotDataMore[1]=theApp.uploadqueue->GetUploadQueueLength();
	m_dPlotDataMore[2]=0;//theApp.uploadqueue->GetWaitingUserCount();
	m_dPlotDataMore[3]=myStats[1];

	//for (int i=0;i<4;i++) if (m_dPlotDataMore[i]>theApp.glob_prefs->GetStatsMax()) {resize=true;theApp.glob_prefs->GetStatsMax()=(int)m_dPlotDataMore[i];}
	//if (resize) m_Statistics.SetRanges(0, theApp.glob_prefs->GetStatsMax()+15) ;
	 
	m_Statistics->AppendPoints(m_dPlotDataMore);
}

void CStatisticsDlg::UpdateConnectionsStatus(){
	if( peakconnections < activeconnections )
		peakconnections = activeconnections;
	if( theApp.serverconnect->IsConnected() ){
	totalconnectionchecks++;
	float percent;
	percent = (float)((float)(totalconnectionchecks-1)/(float)totalconnectionchecks);
	if( percent > .99 )
		percent = (float).99;
	averageconnections = (averageconnections*percent) + (float)((float)activeconnections*(float)(1-percent));
	}
}

float CStatisticsDlg::GetMaxConperFiveModifier(){
	//This is a alpha test.. Will clean up for b version.
	float SpikeSize = theApp.listensocket->GetOpenSockets() - averageconnections ;
	if ( SpikeSize < 1 )
		return 1;
	float SpikeTolerance = 25*(float)theApp.glob_prefs->GetMaxConperFive()/(float)10;
	if ( SpikeSize > SpikeTolerance )
		return 0;
	float Modifier = (1-(SpikeSize/SpikeTolerance));
	return Modifier;
}

void CStatisticsDlg::RecordRate() {
	if (theApp.stat_transferStarttime==0) return;

	// every second
	downrateHistory.push_front(theApp.stat_sessionReceivedBytes);
	uprateHistory.push_front(theApp.stat_sessionSentBytes);
	
	// limit to maxmins 
	while ((int)downrateHistory.size()>(int)( theApp.glob_prefs->GetStatsAverageMinutes()*60)) downrateHistory.pop_back();
	while ((int)uprateHistory.size()>(int)( theApp.glob_prefs->GetStatsAverageMinutes()*60)) uprateHistory.pop_back();

}

void CStatisticsDlg::ShowStatistics() {
	CString cbuffer;
	CString cbuffer2;
	bool resize;
	DWORD running;
	int myStats[10];
	float DownAvgRate;

	resize=false;
	theApp.downloadqueue->GetDownloadStats(myStats);

	uint64 DownOHTotal = theApp.downloadqueue->GetDownDataOverheadFileRequest() + theApp.downloadqueue->GetDownDataOverheadSourceExchange() + theApp.downloadqueue->GetDownDataOverheadServer() + theApp.downloadqueue->GetDownDataOverheadOther();
	uint64 DownOHTotalPackets = theApp.downloadqueue->GetDownDataOverheadFileRequestPackets() + theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets() + theApp.downloadqueue->GetDownDataOverheadServerPackets() + theApp.downloadqueue->GetDownDataOverheadOtherPackets();
	cbuffer.Format(GetResString(IDS_STATS_DDATA),CastItoXBytes( theApp.stat_sessionReceivedBytes).GetData(),	CastItoXBytes( theApp.stat_sessionReceivedBytes+theApp.glob_prefs->GetTotalDownloaded()).GetData());
	stattree->SetItemText(down1, cbuffer);
	cbuffer.Format(GetResString(IDS_TOVERHEAD),	CastItoXBytes(DownOHTotal).GetData(), CastItoIShort(DownOHTotalPackets).GetData());
	stattree->SetItemText(down2, cbuffer);
	cbuffer.Format(GetResString(IDS_FROVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadFileRequest()).GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadFileRequestPackets()).GetData());
	stattree->SetItemText(down3, cbuffer);
	cbuffer.Format(GetResString(IDS_SSOVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadSourceExchange()).GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets()).GetData() );
	stattree->SetItemText(down4, cbuffer);
	cbuffer.Format(GetResString(IDS_SOVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadServer()).GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadServerPackets()).GetData());
	stattree->SetItemText(down5, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FOUNDSRC),myStats[0]);
	stattree->SetItemText(down6, cbuffer);
    cbuffer.Format(GetResString(IDS_STATS_ACTDL),myStats[1]);
	stattree->SetItemText(down7, cbuffer);
	uint64 UpOHTotal = theApp.uploadqueue->GetUpDataOverheadFileRequest() + theApp.uploadqueue->GetUpDataOverheadSourceExchange() + theApp.uploadqueue->GetUpDataOverheadServer() + theApp.uploadqueue->GetUpDataOverheadOther();
	uint64 UpOHTotalPackets = theApp.uploadqueue->GetUpDataOverheadFileRequestPackets() + theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets() + theApp.uploadqueue->GetUpDataOverheadServerPackets() + theApp.uploadqueue->GetUpDataOverheadOtherPackets();
	cbuffer.Format(GetResString(IDS_STATS_UDATA),CastItoXBytes( theApp.stat_sessionSentBytes).GetData(),CastItoXBytes( theApp.stat_sessionSentBytes+theApp.glob_prefs->GetTotalUploaded()).GetData());
	stattree->SetItemText(up1, cbuffer);
	cbuffer.Format(GetResString(IDS_TOVERHEAD), CastItoXBytes( UpOHTotal).GetData(), CastItoIShort(UpOHTotalPackets).GetData());
	stattree->SetItemText(up2, cbuffer);
	cbuffer.Format(GetResString(IDS_FROVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadFileRequest()).GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadFileRequestPackets()).GetData());
	stattree->SetItemText(up3, cbuffer);
	cbuffer.Format(GetResString(IDS_SSOVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadSourceExchange()).GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets()).GetData());
	stattree->SetItemText(up4, cbuffer);
	cbuffer.Format(GetResString(IDS_SOVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadServer()).GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadServerPackets()).GetData());
	stattree->SetItemText(up5, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_ACTUL),theApp.uploadqueue->GetUploadQueueLength());
	stattree->SetItemText(up6, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_WAITINGUSERS),theApp.uploadqueue->GetWaitingUserCount());
	stattree->SetItemText(up7, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_SUCCUPCOUNT),theApp.uploadqueue->GetSuccessfullUpCount());
	stattree->SetItemText(up8, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FAILUPCOUNT),theApp.uploadqueue->GetFailedUpCount());
	stattree->SetItemText(up9, cbuffer);
	running=theApp.uploadqueue->GetAverageUpTime();
	cbuffer.Format(GetResString(IDS_STATS_AVEUPTIME),CastSecondsToHM(running).GetData());
	stattree->SetItemText(up10, cbuffer);

	if (theApp.stat_transferStarttime>0) {
		cbuffer.Format(GetResString(IDS_STATS_AVGDL),GetAvgDownloadRate(AVG_SESSION));
		stattree->SetItemText(con1, cbuffer);

		cbuffer.Format(GetResString(IDS_STATS_AVGUL),GetAvgUploadRate(AVG_SESSION));
		stattree->SetItemText(con2, cbuffer);

		DownAvgRate=GetAvgDownloadRate(AVG_SESSION);
		if (maxDownavg<DownAvgRate) maxDownavg=DownAvgRate;
		cbuffer.Format(GetResString(IDS_STATS_MAXAVGDL),maxDownavg);
		stattree->SetItemText(con12, cbuffer);
		cbuffer.Format(GetResString(IDS_STATS_MAXDL),maxDown);
		stattree->SetItemText(con13, cbuffer);
	}
	if (theApp.stat_reconnects>0) cbuffer.Format(GetResString(IDS_STATS_RECONNECTS),theApp.stat_reconnects-1);
		else cbuffer.Format(GetResString(IDS_STATS_RECONNECTS),0);
	stattree->SetItemText(con3, cbuffer);

	if (theApp.stat_transferStarttime==0) cbuffer.Format(GetResString(IDS_STATS_WAITTRANSF)); else {
		running=(GetTickCount()-theApp.stat_transferStarttime)/1000;
		cbuffer.Format(GetResString(IDS_TRANSFERTIME),CastSecondsToHM(running).GetData());
	}
	stattree->SetItemText(con4, cbuffer);

	if (theApp.stat_serverConnectTime==0) cbuffer.Format(GetResString(IDS_STATS_WAITCONN)); else {
		running=(GetTickCount()-theApp.stat_serverConnectTime)/1000;
		cbuffer.Format(GetResString(IDS_STATS_CONNECTEDSINCE),CastSecondsToHM(running).GetData());
	}
	stattree->SetItemText(con5, cbuffer);

	if (theApp.stat_sessionReceivedBytes>0 && theApp.stat_sessionSentBytes>0 )
		if (theApp.stat_sessionReceivedBytes<theApp.stat_sessionSentBytes) {
			cbuffer.Format("%s %.2f : 1",GetResString(IDS_STATS_RATIO).GetData(),(float)theApp.stat_sessionSentBytes/theApp.stat_sessionReceivedBytes);
			stattree->SetItemText(tran0, cbuffer);
		} else {
			cbuffer.Format("%s 1 : %.2f",GetResString(IDS_STATS_RATIO).GetData(),(float)theApp.stat_sessionReceivedBytes/theApp.stat_sessionSentBytes);
			stattree->SetItemText(tran0, cbuffer);
		}

	// shared files stats
	cbuffer.Format(GetResString(IDS_SHAREDFILESCOUNT),theApp.sharedfiles->GetCount());stattree->SetItemText(shar1, cbuffer);

	uint64 allsize=theApp.sharedfiles->GetDatasize();
	cbuffer.Format(GetResString(IDS_SF_SIZE),CastItoXBytes(allsize).GetData());stattree->SetItemText(shar2, cbuffer);
	
	if(theApp.sharedfiles->GetCount() != 0)
		cbuffer2.Format( "%s", CastItoXBytes((uint64)allsize/theApp.sharedfiles->GetCount()).GetData());
	else {
		cbuffer2 = "-";
	}
	cbuffer.Format(GetResString(IDS_SF_AVERAGESIZE),cbuffer2.GetData());
	stattree->SetItemText(shar3, cbuffer);
	// get clientversion-counts

	// statsclientstatus : original idea and code by xrmb
	
	CMap<uint8, uint8, uint32, uint32> clientStatus;
	CMap<uint16, uint16, uint32, uint32> clientVersionEDonkey;
	CMap<uint16, uint16, uint32, uint32> clientVersionEDonkeyHybrid;
	CMap<uint8, uint8, uint32, uint32> clientVersionEMule;
	uint32 totalclient;
	theApp.clientlist->GetStatistics(totalclient, myStats, &clientStatus, &clientVersionEDonkey, &clientVersionEDonkeyHybrid, &clientVersionEMule);
	totalclient -= myStats[0];
	if( !totalclient )
		totalclient = 1;
	cbuffer.Format(_("eMule: %i (%1.1f%%)"),myStats[2],(double)100*myStats[2]/totalclient);stattree->SetItemText(cli1, cbuffer);
	cbuffer.Format(_("lMule: %i (%1.1f%%)"),myStats[6],(double)100*myStats[6]/totalclient);stattree->SetItemText(cli8, cbuffer);
	cbuffer.Format(_("eDonkeyHybrid: %i (%1.1f%%)"),myStats[4],(double)100*myStats[4]/totalclient);stattree->SetItemText(cli2, cbuffer);
	cbuffer.Format(_("eDonkey: %i (%1.1f%%)"),myStats[1],(double)100*myStats[1]/totalclient);stattree->SetItemText(cli3, cbuffer);
	cbuffer.Format(_("cDonkey: %i (%1.1f%%)"),myStats[5],(double)100*myStats[5]/totalclient);stattree->SetItemText(cli4, cbuffer);
	cbuffer.Format(_("Old MLDonkey: %i (%1.1f%%)"),myStats[3],(double)100*myStats[3]/totalclient);stattree->SetItemText(cli5, cbuffer);
	cbuffer.Format(_("New MLDonkey: %i (%1.1f%%)"),myStats[7],(double)100*myStats[7]/totalclient);stattree->SetItemText(cli9, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_UNKNOWNCLIENT).GetData(),myStats[0]);stattree->SetItemText(cli6, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FILTEREDCLIENTS).GetData(),theApp.stat_filteredclients);stattree->SetItemText(cli7, cbuffer);
	
	//if (stattree->GetItemState(cli3, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
	if(stattree->IsExpanded(cli3)) {

		uint32 totcnt = myStats[1];

		//--- find top 4 eDonkey client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEDonkey.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint16	ver;
				uint32	cnt;
				clientVersionEDonkey.GetNextAssoc(pos, ver, cnt);
				if(currtop<ver && ver<lasttop && ver != 0x91)
				{
					double percent = (double)cnt/totcnt;
					if( lasttop == 0xFFFFFFFF &&
					    ( (totcnt > 75 && ((cnt <= 2) || percent < 0.01)) ||
					      (totcnt > 50 && cnt <= 1)
					    )
					  )
						continue;
					topper=percent;
					topver=ver;
					topcnt=cnt;
					currtop=ver;
				}
			}
			lasttop=currtop;
			currtop=0;
			if(topcnt)
				cbuffer.Format("v%i: %i (%1.1f%%)", topver, topcnt, topper*100);
			else
				cbuffer="";

			stattree->SetItemText(cli_versions[i+8], cbuffer);
		}
	}

	//if (stattree->GetItemState(cli2, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
	if(stattree->IsExpanded(cli2)) {

		uint32 totcnt = myStats[4];

		//--- find top 4 eDonkey client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEDonkeyHybrid.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint16	ver;
				uint32	cnt;
				clientVersionEDonkeyHybrid.GetNextAssoc(pos, ver, cnt);
				if(currtop<ver && ver<lasttop && ver != 0x91)
				{
					double percent = (double)cnt/totcnt;
					if( lasttop == 0xFFFFFFFF &&
					    ( (totcnt > 75 && ((cnt <= 2) || percent < 0.01)) ||
					      (totcnt > 50 && cnt <= 1)
					    )
					  )
						continue;
					topper=percent;
					topver=ver;
					topcnt=cnt;
					currtop=ver;
				}
			}
			lasttop=currtop;
			currtop=0;
			if(topcnt)
				cbuffer.Format("v%i: %i (%1.1f%%)", topver, topcnt, topper*100);
			else
				cbuffer="";

			stattree->SetItemText(cli_versions[i+4], cbuffer);
		}
	}

	//if (stattree->GetItemState(cli1, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
	if(stattree->IsExpanded(cli1)) {
		uint32 totcnt = myStats[2];

		//--- find top 4 eMule client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEMule.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint8	ver;
				uint32	cnt;
				clientVersionEMule.GetNextAssoc(pos, ver, cnt);
				if(currtop<ver && ver<lasttop )
				{
					double percent = (double)cnt/totcnt;
					if( lasttop == 0xFFFFFFFF &&
					    ( (totcnt > 75 && ((cnt <= 2) || percent < 0.01)) ||
					      (totcnt > 50 && cnt <= 1)
					    )
					  )
						continue;
					topper=percent;
					topver=ver;
					topcnt=cnt;
					currtop=ver;
				}
			}
			lasttop=currtop;
			currtop=0;
			if(topcnt)
				cbuffer.Format("v0.%02X: %i (%1.1f%%)", topver, topcnt, topper*100);
			else
				cbuffer="";

			stattree->SetItemText(cli_versions[i], cbuffer);
		}
		// xrmb
	}

	// get serverstats
	uint32 servtotal;
	uint32 servfail;
	uint32 servuser;
	uint32 servfile;
	uint32 servtuser;
	uint32 servtfile;
	float servocc;
	theApp.serverlist->GetStatus( servtotal, servfail, servuser, servfile, servtuser, servtfile,servocc);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WORKING).GetData(),servtotal-servfail);stattree->SetItemText(srv1, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_FAIL).GetData(),servfail);stattree->SetItemText(srv2, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_TOTAL).GetData(),servtotal);stattree->SetItemText(srv3, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_DELCOUNT).GetData(),theApp.serverlist->GetDeletedServerCount());stattree->SetItemText(srv4, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WUSER).GetData(),servuser);stattree->SetItemText(srv5, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WFILE).GetData(),servfile);stattree->SetItemText(srv6, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_USER).GetData(),servtuser);stattree->SetItemText(srv7, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_FILE).GetData(),servtfile);stattree->SetItemText(srv8, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_ACTIVECON).GetData(),activeconnections);stattree->SetItemText(con6, cbuffer);
	cbuffer.Format(GetResString(IDS_SF_SRVOCC),servocc);stattree->SetItemText(srv9, cbuffer);
	uint32 m_itemp = theApp.listensocket->GetMaxConnectionReached();
	if( m_itemp != m_ilastMaxConnReached ){
	  char osDate[60];
		//_strtime( osTime );
		//_strdate( osDate );

		time_t mytime=time(NULL);
		struct tm* now=localtime(&mytime);
		strftime(osDate,sizeof(osDate)-1,"%d.%m.%Y %H:%M:%S",now);

		cbuffer.Format("%s: %i : %s",GetResString(IDS_SF_MAXCONLIMITREACHED).GetData(),m_itemp,osDate);stattree->SetItemText(con7, cbuffer);
		m_ilastMaxConnReached = m_itemp;
	}
	else if( m_itemp == 0 ){
		cbuffer.Format("%s: %i",GetResString(IDS_SF_MAXCONLIMITREACHED).GetData(),m_itemp);stattree->SetItemText(con7, cbuffer);}

	if(theApp.serverconnect->IsConnected()){
		cbuffer.Format("%s: %i",GetResString(IDS_SF_AVGCON).GetData(),(int)averageconnections);stattree->SetItemText(con8, cbuffer);
	}
	else{
		stattree->SetItemText(con8, GetResString(IDS_STATS_WAITCONN));
	}
	cbuffer.Format("%s: %i",GetResString(IDS_SF_PEAKCON).GetData(),peakconnections);
	stattree->SetItemText(con9, cbuffer);
}

float CStatisticsDlg::GetAvgDownloadRate(int averageType) {
	if (averageType==AVG_SESSION) {
		if (theApp.stat_transferStarttime ==0) return 0;

		DWORD running=(GetTickCount()-theApp.stat_transferStarttime)/1000;
		if (running<5) return 0;

		return (float)(theApp.stat_sessionReceivedBytes/1024) / running;
	} else {
		if (downrateHistory.size()==0) return 0;
		uint64 sum;
		sum=downrateHistory.front();
		if ((int)downrateHistory.size()>=(int)theApp.glob_prefs->GetStatsAverageMinutes()*60) sum-=downrateHistory.back();

		return (float)(sum/1024)/downrateHistory.size();
	}
}

float CStatisticsDlg::GetAvgUploadRate(int averageType) {
	if (averageType==AVG_SESSION) {
		if (theApp.stat_transferStarttime==0) return 0;

		DWORD running=(GetTickCount()-theApp.stat_transferStarttime)/1000;
		if (running<5) return 0;

		return (float)(theApp.stat_sessionSentBytes/1024) / running;
	} else  {
		if (uprateHistory.size()==0) return 0;
		uint64 sum=uprateHistory.front();

		if ((int)uprateHistory.size()>=(int)(theApp.glob_prefs->GetStatsAverageMinutes()*60)) sum-=uprateHistory.back();

		return (float)(sum/1024)/uprateHistory.size();
	}
}

#if 0
void CStatisticsDlg::OnShowWindow(BOOL bShow,UINT nStatus){

}

void CStatisticsDlg::OnSize(UINT nType, int cx, int cy)
{
	CResizableDialog::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here
	//this will cause COScopeCtrl::OnSizeCall
	CRect rc;
	GetDlgItem(IDC_UPLOAD)->GetWindowRect(&rc);
	ScreenToClient(&rc);
	m_DownloadOMeter.MoveWindow(&rc);

}  //OnSize
#endif

void CStatisticsDlg::ShowInterval() {
  //EnableWindow( FALSE );

	int shownSecs=319*theApp.glob_prefs->GetTrafficOMeterInterval();
	
	if (theApp.glob_prefs->GetTrafficOMeterInterval()==0) {
		m_DownloadOMeter->SetXUnits(GetResString(IDS_STOPPED)); 
		m_UploadOMeter->SetXUnits(GetResString(IDS_STOPPED)); 
	} else
	{
		char buffer[50];
		wxString tmpstr=CastSecondsToHM(shownSecs);
		m_UploadOMeter->SetXUnits(tmpstr.GetData() );
		m_DownloadOMeter->SetXUnits(tmpstr.GetData()); 
	}

	//UpdateData(FALSE);
	//EnableWindow( TRUE );
}

void CStatisticsDlg::SetARange(bool SetDownload,int maxValue){
	if (SetDownload) {
		m_DownloadOMeter->SetRange(0, maxValue+4, 0);
		m_DownloadOMeter->SetRange(0, maxValue+4, 1);
		m_DownloadOMeter->SetRange(0, maxValue+4, 2);
	}else{
		m_UploadOMeter->SetRange(0, maxValue+4, 0) ;
		m_UploadOMeter->SetRange(0, maxValue+4, 1);
		m_UploadOMeter->SetRange(0, maxValue+4, 2);
	}
}

#if 0
void CStatisticsDlg::Localize(){
	GetDlgItem(IDC_STATIC_D3)->SetWindowText(GetResString(IDS_ST_DOWNLOAD));
	GetDlgItem(IDC_STATIC_U)->SetWindowText(GetResString(IDS_ST_UPLOAD));
	GetDlgItem(IDC_STATIC_D)->SetWindowText(GetResString(IDS_ST_CURRENT));
	GetDlgItem(IDC_STATIC_U2)->SetWindowText(GetResString(IDS_ST_CURRENT));
	GetDlgItem(IDC_STATIC_D2)->SetWindowText(GetResString(IDS_ST_SESSION));
	GetDlgItem(IDC_STATIC_U3)->SetWindowText(GetResString(IDS_ST_SESSION));
	GetDlgItem(IDC_STATIC_S2)->SetWindowText(GetResString(IDS_ST_ACTIVED));
	GetDlgItem(IDC_STATIC_S0)->SetWindowText(GetResString(IDS_ST_ACTIVEC));
	GetDlgItem(IDC_STATIC_S1)->SetWindowText(GetResString(IDS_ST_ACTIVEU));
	GetDlgItem(IDC_STATIC_S3)->SetWindowText(GetResString(IDS_ST_WAITINGU));
	CString value;value.Format(" (%u mins)",theApp.glob_prefs->GetStatsAverageMinutes() );
	GetDlgItem(IDC_TIMEAVG1)->SetWindowText(GetResString(IDS_AVG) + value );
	GetDlgItem(IDC_TIMEAVG2)->SetWindowText(GetResString(IDS_AVG) + value);
}
#endif

// the idea: we must dispatch this request to the main thread as web thread
// can't touch the GUI controls. Only allowed function is wxPostEvent which
// unfortunately just passes the event, so we must implement a wxCondition
// so we can wait until the main thread has processed the request and built
// a valid string for us.
wxString CStatisticsDlg::ExportHTML() {
  // only one shall pass
  wxCriticalSectionLocker locker(exportCrit);
  // then lock the signalling mutex
  wxCondition myCond(exportMutex);
  exportCondition=&myCond;
  exportMutex.Lock();
  // post the message
  wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED,ID_EXPORT_HTML);
  wxPostEvent(this,evt);
  // and wait until it is completed
  exportCondition->Wait();
  // and now we can return the string
  exportMutex.Unlock();
  printf("*** WEB THREAD: returning the value\n");
  return exportString;
}

void CStatisticsDlg::ExportHTMLEvent(wxEvent& evt) {
        int8 ix;
        wxString temp;
        wxString text="";
        wxTreeItemId item;
         
	// update it
	ShowStatistics();

        item=stattree->GetRootItem();
        text=stattree->GetItemText(item);
        while (item!=NULL)
        {
                item=stattree->GetNextVisible(item);
                if (item==NULL) break;
 
                stattree->Expand(item);//,TVE_EXPAND);
 
                temp="";
                for (ix=0;ix<3*(int)stattree->GetItemData(item);ix++) temp+="&nbsp;";
 
                text+="<br>"+temp+stattree->GetItemText(item);
        }
 
	// set the string
	exportString=text;
	// and signal
	printf("** MAIN THREAD: Return value ready.\n");
	wxMutexLocker locker(exportMutex);
	exportCondition->Broadcast();
	printf("** MAIN THREAD: All done.\n");
}
